How to make an array of arrays in Java
Asked Answered
D

4

147

Hypothetically, I have 5 string array objects:

String[] array1 = new String[];
String[] array2 = new String[];
String[] array3 = new String[];
String[] array4 = new String[];
String[] array5 = new String[];

and I want another array object to contain those 5 string array objects. How do I do it? Can I put it in another array?

Doubletongued answered 24/1, 2011 at 10:50 Comment(2)
Noob questions can be serious. In fact, they frequently are. :-)Ibson
Pertinent question, and answer is not obvious for who knows how the memory alignment is done. +1Morey
O
187

Like this:

String[][] arrays = { array1, array2, array3, array4, array5 };

or

String[][] arrays = new String[][] { array1, array2, array3, array4, array5 };

(The latter syntax can be used in assignments other than at the point of the variable declaration, whereas the shorter syntax only works with declarations.)

Obbard answered 24/1, 2011 at 10:54 Comment(9)
Could you explain further what the second syntax does? It's kind of unclear to me.Doubletongued
@Terence: It does the same as the first: It creates an array of string array references, initialized to the values array1, array2, array3, array4 and array5 - each of which is in itself a string array reference.Obbard
Quick question: How will I do this at run time if I have no idea how many array objects will be created?Doubletongued
@Terence: Can you give a more specific example? When you're specifying the initial values at compile-time, you do know the size. Do you mean something like new String[10][]?Obbard
Yes. Similar to Peter's answer.Doubletongued
@JonSkeet can this be helpful in any way when trying to perform a cartesian product of a long list of api paramerters ?Circumfluent
@valik: In that case I'd consider creating a class to represent "the set of parameters" instead of using an array.Obbard
#51162262 @JonSkeet i would direct u to my question if you have an idea please commentCircumfluent
@Terence, you would write something like: String[][] arrays = { {"A", "1"}, {"B", "2"}, {"C", "3"}, {"D", "4"}, {"E", "5"} };Issykkul
C
86

try

String[][] arrays = new String[5][];
Changchangaris answered 24/1, 2011 at 10:51 Comment(5)
this one is more flexiableAment
Shouldn't you define a fixed size on your array?Tanah
@Tanah it is fixed to 5. Setting the next level pre-allocates them but this can be changed so setting it might not be useful.Changchangaris
How do I insert data into the array? If its dynamic data?Arlo
@PrakharMohanSrivastava you can set the elements individually: arrays[0] = new String[] {"a", "b", "c"} or use a temp List: <pre><code> List<String[]> myList = new ArrayList<>(); myList.add(new String[]{"a", "b", "c"}); myList.add(new String[]{"d", "e", "f"}); myList.toArray(arrays); </code></pre>Intranuclear
M
32

While there are two excellent answers telling you how to do it, I feel that another answer is missing: In most cases you shouldn't do it at all.

Arrays are cumbersome, in most cases you are better off using the Collection API.

With Collections, you can add and remove elements and there are specialized Collections for different functionality (index-based lookup, sorting, uniqueness, FIFO-access, concurrency etc.).

While it's of course good and important to know about Arrays and their usage, in most cases using Collections makes APIs a lot more manageable (which is why new libraries like Google Guava hardly use Arrays at all).

So, for your scenario, I'd prefer a List of Lists, and I'd create it using Guava:

List<List<String>> listOfLists = Lists.newArrayList();
listOfLists.add(Lists.newArrayList("abc","def","ghi"));
listOfLists.add(Lists.newArrayList("jkl","mno","pqr"));
Muezzin answered 24/1, 2011 at 11:14 Comment(3)
A bit more complicated than String[ ][ ], but permits more operations such as concatenating data. However, your solution does not ensure the size of the data, which can be a problem.Morey
@Morey if necessary, it is always possible to write a List decorator that only accepts a certain number of items.Muezzin
Exact, decorators/wrappers are a good way to ensure coherence. Thus, the way we are speaking about is far more complex than simple arrays. What I have done is a small utility class Array2D<T> which encapsulates some basic methods such as exixts(...) etc. I posted this below.Morey
M
6

there is the class I mentioned in the comment we had with Sean Patrick Floyd : I did it with a peculiar use which needs WeakReference, but you can change it by any object with ease.

Hoping this can help someone someday :)

import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Queue;


/**
 *
 * @author leBenj
 */
public class Array2DWeakRefsBuffered<T>
{
    private final WeakReference<T>[][] _array;
    private final Queue<T> _buffer;

    private final int _width;

    private final int _height;

    private final int _bufferSize;

    @SuppressWarnings( "unchecked" )
    public Array2DWeakRefsBuffered( int w , int h , int bufferSize )
    {
        _width = w;
        _height = h;
        _bufferSize = bufferSize;
        _array = new WeakReference[_width][_height];
        _buffer = new LinkedList<T>();
    }

    /**
     * Tests the existence of the encapsulated object
     * /!\ This DOES NOT ensure that the object will be available on next call !
     * @param x
     * @param y
     * @return
     * @throws IndexOutOfBoundsException
     */public boolean exists( int x , int y ) throws IndexOutOfBoundsException
    {
        if( x >= _width || x < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ x = " + x + "]" );
        }
        if( y >= _height || y < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ y = " + y + "]" );
        }
        if( _array[x][y] != null )
        {
            T elem = _array[x][y].get();
            if( elem != null )
            {
            return true;
            }
        }
        return false;
    }

    /**
     * Gets the encapsulated object
     * @param x
     * @param y
     * @return
     * @throws IndexOutOfBoundsException
     * @throws NoSuchElementException
     */
    public T get( int x , int y ) throws IndexOutOfBoundsException , NoSuchElementException
    {
        T retour = null;
        if( x >= _width || x < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ x = " + x + "]" );
        }
        if( y >= _height || y < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ y = " + y + "]" );
        }
        if( _array[x][y] != null )
        {
            retour = _array[x][y].get();
            if( retour == null )
            {
            throw new NoSuchElementException( "Dereferenced WeakReference element at [ " + x + " ; " + y + "]" );
            }
        }
        else
        {
            throw new NoSuchElementException( "No WeakReference element at [ " + x + " ; " + y + "]" );
        }
        return retour;
    }

    /**
     * Add/replace an object
     * @param o
     * @param x
     * @param y
     * @throws IndexOutOfBoundsException
     */
    public void set( T o , int x , int y ) throws IndexOutOfBoundsException
    {
        if( x >= _width || x < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (set) : [ x = " + x + "]" );
        }
        if( y >= _height || y < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (set) : [ y = " + y + "]" );
        }
        _array[x][y] = new WeakReference<T>( o );

        // store local "visible" references : avoids deletion, works in FIFO mode
        _buffer.add( o );
        if(_buffer.size() > _bufferSize)
        {
            _buffer.poll();
        }
    }

}

Example of how to use it :

// a 5x5 array, with at most 10 elements "bufferized" -> the last 10 elements will not be taken by GC process
Array2DWeakRefsBuffered<Image> myArray = new Array2DWeakRefsBuffered<Image>(5,5,10);
Image img = myArray.set(anImage,0,0);
if(myArray.exists(3,3))
{
    System.out.println("Image at 3,3 is still in memory");
}
Morey answered 29/11, 2012 at 14:2 Comment(2)
+1 for your effort, but: instead of initializing your int fields to -1 and reassigning them in the Constructor, you should make them final and assign them only in the Constructor.Muezzin
@Sean : I modified the code (posted new one with "no-GC buffer", including your wise comment.Morey

© 2022 - 2024 — McMap. All rights reserved.